

#pragma once

#include "../DefinesCore.hpp"
#include <string>

CYBERTRON_BEGIN

class AsioSocketAsync;
class SocketEventHandlerList;

enum ESocketStatus
{
	ESocketStatus_Closed, 
	ESocketStatus_Connecting, 
	ESocketStatus_Connected, 
};

// Base class, should not be used directly.
class SocketBase : public std::enable_shared_from_this<SocketBase>
{
public:
	CybertronCoreAPI SocketBase();
	CybertronCoreAPI virtual ~SocketBase();

	CybertronCoreAPI void addHandler(SocketEventHandlerPtr pHandler);
	CybertronCoreAPI void removeHandler(SocketEventHandlerPtr pHandler);

	CybertronCoreAPI void send(const Message& msg);
	CybertronCoreAPI void send(
		std::uint16_t msgId,
		const google::protobuf::MessageLite& msg);
	CybertronCoreAPI void sendHeartbeat();

	CybertronCoreAPI virtual void close(const char* reason);

	CybertronCoreAPI const std::string& getRemoteIp() const;
	CybertronCoreAPI int getRemotePort() const;
	CybertronCoreAPI unsigned int getLastMessageTime() const;

	CybertronCoreAPI ESocketStatus getStatus() const;

	CybertronCoreAPI void setId(int id);
	CybertronCoreAPI int getId() const;

	[[deprecated("Only use for unit test")]]
	void* getSocket() const;
protected:
	friend class SocketTcpServer;

	CybertronCoreAPI void setImpl(std::shared_ptr<AsioSocketAsync> pImpl);

private:
	void closeThis(const char* reason);

private:
	SocketBase(const SocketBase&);
	SocketBase(SocketBase&&);
	SocketBase& operator = (const SocketBase&);
	SocketBase& operator = (SocketBase&&);

protected:
	int mId;
	std::shared_ptr<AsioSocketAsync> mpImpl;
	std::shared_ptr<SocketEventHandlerList> mEventHandlers;
};

CYBERTRON_END
